package io.gps.datatransfer;

import java.net.InetSocketAddress;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ConcurrentLinkedQueue;

import io.gps.datatransfer.codec.TCPCodecFactory;
import io.gps.datatransfer.command.DevServer;
import io.gps.datatransfer.command.GpsMsg;
import io.gps.datatransfer.task.taskentity.SendDownMsgWork;
import io.gps.datatransfer.utils.ByteUtils;
import io.gps.datatransfer.utils.SysDef;
import io.gps.datatransfer.utils.Utils;
import org.apache.log4j.Logger;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.transport.socket.SocketConnector;
import org.apache.mina.transport.socket.nio.NioSocketConnector;


/**
 * 转发服务控制器
 * @author bcs
 * @version 2.0, $Date: 2020-11-26 13:06:17 $
 */
public class CenterChannel extends IoHandlerAdapter {

    public boolean isConnectedServer=false;
    private static Logger logger = Logger.getLogger(CenterChannel.class);
    /**
     * 上送服务器对象
     */
    public DevServer devServer;
    public String key;

    private SocketConnector connector;
    /**
     * 通信会话session
     */
    private IoSession session;
    private long lastHandTime=0;
    private ConnectFuture connectFuture;

    /**
     * 车辆 指令队列
     */
    public ConcurrentLinkedQueue<IoBuffer> queueMsg = new ConcurrentLinkedQueue<IoBuffer>();


    public CenterChannel(DevServer devServer, String key) {
        this.devServer = devServer;
        this.key=key;
    }


    public void Login(){
        //检查是否到达运行时间
        Date thisDate=new Date();
        long thisLongTime=System.currentTimeMillis();
        String timeStr=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(thisDate);
        try{
            if((lastHandTime==0||(thisLongTime-lastHandTime>60000))&&(session==null||session.isClosing())){
                isConnectedServer = false;
                lastHandTime=System.currentTimeMillis();
                logger.error((timeStr+" 与中心服务器: " + devServer.getServerid() + " 请求链接"));
                connect();
            }else{
                if(session!=null){
                    // 发送缓存指令
                    sendMsg();
                    lastHandTime=System.currentTimeMillis();
                    isConnectedServer = true;
                }
            }

        }catch(Exception e){
            lastHandTime=System.currentTimeMillis();
            logger.error(timeStr+" 与中心服务器: " +devServer.getServerid()  + " 链接失败，等待 60 秒后重新链接",e);
            disconnect();

        }
    }

    /**
     * 是否已建立链接
     * @return Boolean
     */
    public boolean isConnected() {
        return this.connectFuture.isConnected();
    }

    /**
     * 链接
     */
    public void connect() throws Exception {
        this.connector = new NioSocketConnector();
        this.connector.setHandler(this);
        int ideleTime=20;
        if(SysDef.IS_SET_ONE|| !devServer.isIsmaster()){
            ideleTime=180;
        }
        this.connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TCPCodecFactory()));
        this.connector.getSessionConfig().setIdleTime(IdleStatus.WRITER_IDLE,ideleTime);
        this.connector.getSessionConfig().setSoLinger(0);
        this.connectFuture = connector.connect(new InetSocketAddress(devServer.getIp(), devServer.getPort()));
        this.connectFuture.awaitUninterruptibly(SysDef.CONNECT_TIME_OUT);
    }
    /**
     * 关闭session
     */
    public void disconnect() {
        this.isConnectedServer = false;
        if (this.session != null) {
            this.session.closeNow();
            this.session = null;
            this.connector.dispose();
        }
    }


    @Override
    public void sessionOpened(IoSession session) throws Exception {
        this.session = session;
        this.isConnectedServer = true;
        logger.error(this.key+" 与中心服务器: " + this.devServer.getServerid() + " 链接成功");
    }

    @Override
    public void sessionClosed(IoSession session) throws Exception {
        try{
            session.closeNow();
        }catch (Exception e){
            logger.error(e.getMessage(), e);
        }
        isConnectedServer = false;
        this.session = null;

    }

    @Override
    public void messageReceived(IoSession session, Object message)
            throws Exception {
        GpsMsg gpsMsg= (GpsMsg) message;
        IoBuffer sendObj=null;
        if(gpsMsg.getSrc()!=null&&this.devServer.isIsmaster()){
            byte[] tempdata=gpsMsg.getSrc().array();
            sendObj=IoBuffer.allocate(tempdata.length);
            sendObj.put(tempdata);
            sendObj.flip();
        }
        if(sendObj!=null){
            new SendDownMsgWork(gpsMsg.getSim(),sendObj).run();
            logger.error("实际向设备下发："+ByteUtils.getSouDataLog(sendObj));
        }

    }

    @Override
    public void exceptionCaught(IoSession session, Throwable cause)
            throws Exception {
        Utils.setErrorLink(this.devServer.getServerid(),this.key);
        logger.error(cause.getMessage(),cause);
    }

    public void addMsg(IoBuffer iob){
        this.queueMsg.add(iob);
        if(this.devServer.isIsmaster()){
            sendMsg();
        }
    }

    public void sendMsg(){
        if(this.session!=null&&this.isConnectedServer){
            if(!this.queueMsg.isEmpty()){
                for (int i = 0; i <100 ; i++) {
                    IoBuffer iob=this.queueMsg.poll();
                    if(iob!=null){
                        this.session.write(iob);
                        if(SysDef.IS_LOG){
                            logger.error("TO"+(this.devServer.isIsmaster()?"主":"从")+"服务器"+this.devServer.getServerid()+"发送数据："+ ByteUtils.getSouDataLog(iob));
                        }
                    }else{
                        i=101;
                    }
                }
            }
        }
    }


}

